package com.smile.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.smile.api.FlyApi;
import com.smile.api.OperateLogApi;
import com.smile.api.OrganizationApi;
import com.smile.api.OssApi;
import com.smile.commons.action.ActionUtils;
import com.smile.commons.page.MyBatisPlusPageConverter;
import com.smile.commons.page.R;
import com.smile.commons.time.TimeUtils;
import com.smile.mapper.*;
import com.smile.model.domain.*;
import com.smile.model.dto.DroneDTO;
import com.smile.model.dto.request.*;
import com.smile.model.request.*;
import com.smile.model.response.GetOrganizationByIdResponse;
import com.smile.model.response.response.GetAirportByIdResponseDTO;
import com.smile.model.response.response.GetAirportListResponseDTO;
import com.smile.model.response.response.GetFlyResultResponseDTO;
import com.smile.model.response.response.PayloadDataResponseDTO;
import com.smile.request.AddOperateLogRequest;
import com.smile.service.AirportService;
import com.smile.service.FlyService;
import com.smile.service.PayloadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FlyServiceImpl implements FlyService {


    @Autowired
    private AirportMapper airportMapper;

    //流媒体推流地址
    @Value("${zlm.url}")
    private String zlmUrl;
    @Autowired
    private FlightTaskMapper flightTaskMapper;

    @Autowired
    private AirportInfoMapper  airportInfoMapper;
    @Autowired
    private OperateLogApi operateLogApi;
    @Autowired
    private DroneMapper droneMapper;
    @Autowired
    private AirportDroneMapper airportDroneMapper;

    @Autowired
    private PayloadService payloadService;

    private ReentrantLock reentrantLock = new ReentrantLock();
    @Autowired
    FlyApi flyApi;
    @Override
    public GetFlyResultResponseDTO takeoffToPoint(FlyRequestDTO editAirportRequestDTO) throws IOException {
        String message = "正常";
        GetFlyResultResponseDTO getFlyResultResponseDTO = new GetFlyResultResponseDTO();
        getFlyResultResponseDTO.setStatus(Boolean.FALSE);
        Integer modeCode = 0;
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", editAirportRequestDTO.getId());
            if (ObjectUtil.isNotNull(editAirportRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", editAirportRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);
                Duration duration =Duration.between(feisuanAirport.getModifyTime(),LocalDateTime.now());
                if(feisuanAirport.getStatus() ==1){
                    //查询机场作业状态 空闲在起飞
                    QueryWrapper<FeisuanAirportInfo> queryWrapper1 = new QueryWrapper<>();
                    queryWrapper1.eq("gateway_sn", feisuanAirport.getGatewaySn());
                    FeisuanAirportInfo feisuanAirportInfo = airportInfoMapper.selectOne(queryWrapper1);
                    if(ObjectUtil.isNotNull(feisuanAirportInfo)){
                        if (feisuanAirportInfo.getModeCode() == 0){
                            UUID uuid = UUID.randomUUID();
                            String flightId =  uuid.toString();
                            System.out.println("flightId:"+flightId);
                            TakeOffToPointRequest takeOffToPointRequest = new TakeOffToPointRequest();
                            takeOffToPointRequest.setGateway(feisuanAirportInfo.getGatewaySn());
                            takeOffToPointRequest.setCommanderFlightMode(1);
                            takeOffToPointRequest.setRthMode(1);
                            takeOffToPointRequest.setFlightId(flightId);
                            takeOffToPointRequest.setCommanderFlightHeight(Float.valueOf(feisuanAirport.getFlightOperationAltitude()));
                            takeOffToPointRequest.setCommanderModeLostAction(0);
                            takeOffToPointRequest.setMaxSpeed(10);
                            takeOffToPointRequest.setRcLostAction(2);
                            takeOffToPointRequest.setFlightSafetyAdvanceCheck(1);
                            takeOffToPointRequest.setTargetHeight(Float.valueOf(feisuanAirport.getFlightOperationAltitude())+feisuanAirportInfo.getHeight().floatValue());
                            takeOffToPointRequest.setRthAltitude(feisuanAirport.getReturnAltitude());
                            takeOffToPointRequest.setSecurityTakeoffHeight(feisuanAirport.getSafeExitAltitude());
                            takeOffToPointRequest.setTargetLongitude(feisuanAirport.getLongitude());
                            takeOffToPointRequest.setTargetLatitude(feisuanAirport.getLatitude());
                            System.out.println("一键起飞参数");
                            System.out.println("takeOffToPointRequest:"+takeOffToPointRequest);
                            R r = flyApi.takeoffToPoint(takeOffToPointRequest);

                            System.out.println("执行结果");
                            System.out.println(takeOffToPointRequest);
//                            System.out.println(r);
                            System.out.println(flightId);
                            FeisuanFlightTask feisuanFlightTask = new FeisuanFlightTask();
                            feisuanFlightTask.setFlightId(flightId);
                            feisuanFlightTask.setGatewaySn(feisuanAirport.getGatewaySn());
                            feisuanFlightTask.setTaskType(2);
                            feisuanFlightTask.setStatus(0);
                            feisuanFlightTask.setCreateTime(LocalDateTime.now());
                            feisuanFlightTask.setModifyTime(LocalDateTime.now());
                            feisuanFlightTask.setStartTime(LocalDateTime.now());

                            QueryWrapper<FeisuanAirportDrone> feisuanAirportDroneQueryWrapper = new QueryWrapper<>();

                            feisuanAirportDroneQueryWrapper.in("airport_id", feisuanAirport.getId());
                            FeisuanAirportDrone feisuanAirportDrone = airportDroneMapper.selectOne(feisuanAirportDroneQueryWrapper);
                            FeisuanDrone feisuanDrone = droneMapper.selectById(feisuanAirportDrone.getDroneId());
                            feisuanFlightTask.setDroneId(feisuanAirportDrone.getDroneId());
                            feisuanFlightTask.setOrganizationId(feisuanAirport.getOrganizationId());
                            flightTaskMapper.insert(feisuanFlightTask);
                            getFlyResultResponseDTO.setStatus(Boolean.TRUE);
                            //开启机场直播
                            LiveStartPushRequest liveStartPushRequest = new LiveStartPushRequest();
                            liveStartPushRequest.setGateway(feisuanAirport.getGatewaySn());
                            liveStartPushRequest.setSn("");
                            liveStartPushRequest.setType("165-0-7");
                            System.out.println("直播推流地址:"+zlmUrl);
                            liveStartPushRequest.setUrl(zlmUrl+"/"+feisuanAirport.getGatewaySn());
                            System.out.println("机场开启直播:"+liveStartPushRequest);
                            flyApi.liveStartPush(liveStartPushRequest);
                            //开启飞行器直播

                            liveStartPushRequest.setGateway(feisuanAirport.getGatewaySn());
                            liveStartPushRequest.setSn(feisuanDrone.getDroneSn());
                            PayloadDataResponseDTO payloadDataResponseDTO =  payloadService.getPayloadData(feisuanAirport.getGatewaySn());
                            if (ObjectUtil.isNotNull(payloadDataResponseDTO)) {
                                liveStartPushRequest.setType(payloadDataResponseDTO.getPayloadIndex());
                                liveStartPushRequest.setUrl(zlmUrl+"/"+feisuanAirport.getGatewaySn()+"@"+feisuanDrone.getDroneSn());
                                flyApi.liveStartPush(liveStartPushRequest);
                            }


                            System.out.println("飞行器开启直播:"+liveStartPushRequest);
                        }else{
                            message = "作业状态:"+feisuanAirportInfo.getModeCode();
                            if(feisuanAirportInfo.getModeCode() == 4){
                                message = "当前无人机处于作业状态请直接进入虚拟座舱";
                            }else if(feisuanAirportInfo.getModeCode() == 1 || feisuanAirportInfo.getModeCode() == 2){
                                message = "机场调试中";
                            }else if(feisuanAirportInfo.getModeCode() == 3){
                                message = "固件升级中";
                            }else if(feisuanAirportInfo.getModeCode() == 5){
                                message = "机场未标定";
                            }
                            modeCode = feisuanAirportInfo.getModeCode();

                            getFlyResultResponseDTO.setCode(modeCode);
                            getFlyResultResponseDTO.setFlighttaskStepCode(feisuanAirportInfo.getFlighttaskStepCode());
                        }
                    }
                }else {
                    message = "无人机不在线或者不是空闲状态";
                }
            }else{
                message = "参数错误";
            }


            System.out.println(message);
//            airportMapper.update(new FeisuanAirport(), updateWrapper);

            Long endTime = System.nanoTime();

            AddOperateLogRequest addOperateLogRequest = new AddOperateLogRequest();
            addOperateLogRequest.setOperateModule("大屏模块");
            addOperateLogRequest.setOperateName("无人机一键起飞");
            addOperateLogRequest.setOperateResult(Boolean.TRUE);
            addOperateLogRequest.setOperateType(1);
            addOperateLogRequest.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
            addOperateLogRequest.setIpAddress(ActionUtils.getIpInfo());
            addOperateLogRequest.setExplorer(ActionUtils.getExplorerInfo());
            addOperateLogRequest.setTimes(endTime - startTime);
            operateLogApi.addOperateLogRequest(addOperateLogRequest);
        } catch (Exception e){
            System.out.println(e.getMessage());
            reentrantLock.unlock();
        }finally {
            reentrantLock.unlock();
        }
        getFlyResultResponseDTO.setMessage(message);
        return getFlyResultResponseDTO;
    }


    @Override
    public GetFlyResultResponseDTO returnHome(FlyRequestDTO editAirportRequestDTO) throws IOException {
        String message = "正常";
        GetFlyResultResponseDTO getFlyResultResponseDTO = new GetFlyResultResponseDTO();
        getFlyResultResponseDTO.setStatus(Boolean.TRUE);
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", editAirportRequestDTO.getId());
            if (ObjectUtil.isNotNull(editAirportRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", editAirportRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);
                Duration duration =Duration.between(feisuanAirport.getModifyTime(),LocalDateTime.now());
                UUID uuid = UUID.randomUUID();
                String flightId =  uuid.toString();
                ReturnHomeRequest returnHomeRequest = new ReturnHomeRequest();
                returnHomeRequest.setFlightId(flightId);
                returnHomeRequest.setGateway(feisuanAirport.getGatewaySn());
                flyApi.returnHome(returnHomeRequest);

            }else{
                message = "参数错误";
                getFlyResultResponseDTO.setStatus(Boolean.FALSE);
            }
            System.out.println(message);
            Long endTime = System.nanoTime();
            AddOperateLogRequest addOperateLogRequest = new AddOperateLogRequest();
            addOperateLogRequest.setOperateModule("大屏模块");
            addOperateLogRequest.setOperateName("无人机返航");
            addOperateLogRequest.setOperateResult(Boolean.TRUE);
            addOperateLogRequest.setOperateType(1);
            addOperateLogRequest.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
            addOperateLogRequest.setIpAddress(ActionUtils.getIpInfo());
            addOperateLogRequest.setExplorer(ActionUtils.getExplorerInfo());
            addOperateLogRequest.setTimes(endTime - startTime);
            operateLogApi.addOperateLogRequest(addOperateLogRequest);
        } catch (Exception e){
            System.out.println(e.getMessage());
            reentrantLock.unlock();
        }finally {
            reentrantLock.unlock();
        }
        getFlyResultResponseDTO.setMessage(message);
        return getFlyResultResponseDTO;
    }

    @Override
    public GetFlyResultResponseDTO flightAuthorityGrab(FlyRequestDTO editAirportRequestDTO) throws IOException {
        String message = "正常";
        GetFlyResultResponseDTO getFlyResultResponseDTO = new GetFlyResultResponseDTO();
        getFlyResultResponseDTO.setStatus(Boolean.TRUE);
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", editAirportRequestDTO.getId());
            if (ObjectUtil.isNotNull(editAirportRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", editAirportRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);

                Duration duration =Duration.between(feisuanAirport.getModifyTime(),LocalDateTime.now());
                UUID uuid = UUID.randomUUID();
                String flightId =  uuid.toString();
                FlightAuthorityGrabRequest flightAuthorityGrabRequest = new FlightAuthorityGrabRequest();
                flightAuthorityGrabRequest.setFlightId(flightId);
                flightAuthorityGrabRequest.setGateway(feisuanAirport.getGatewaySn());
                flyApi.flightAuthorityGrab(flightAuthorityGrabRequest);

            }else{
                message = "参数错误";
                getFlyResultResponseDTO.setStatus(Boolean.FALSE);
            }
//            System.out.println(message);
//            Long endTime = System.nanoTime();
//            AddOperateLogRequest addOperateLogRequest = new AddOperateLogRequest();
//            addOperateLogRequest.setOperateModule("大屏模块");
//            addOperateLogRequest.setOperateName("无人机返航");
//            addOperateLogRequest.setOperateResult(Boolean.TRUE);
//            addOperateLogRequest.setOperateType(1);
//            addOperateLogRequest.setIpAddress(ActionUtils.getIpInfo());
//            addOperateLogRequest.setExplorer(ActionUtils.getExplorerInfo());
//            addOperateLogRequest.setTimes(endTime - startTime);
//            operateLogApi.addOperateLogRequest(addOperateLogRequest);
        } catch (Exception e){
            System.out.println(e.getMessage());
            reentrantLock.unlock();
        }finally {
            reentrantLock.unlock();
        }
        getFlyResultResponseDTO.setMessage(message);
        return getFlyResultResponseDTO;
    }



    @Override
    public GetFlyResultResponseDTO drcModeEnter(FlyRequestDTO editAirportRequestDTO) throws IOException {
        String message = "正常";
        GetFlyResultResponseDTO getFlyResultResponseDTO = new GetFlyResultResponseDTO();
        getFlyResultResponseDTO.setStatus(Boolean.TRUE);
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", editAirportRequestDTO.getId());
            if (ObjectUtil.isNotNull(editAirportRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", editAirportRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);
                DrcModeEnterRequest drcModeEnterRequest = new DrcModeEnterRequest();

                drcModeEnterRequest.setGateway(feisuanAirport.getGatewaySn());
                drcModeEnterRequest.setEnableTls(false);
                drcModeEnterRequest.setExpireTime(null);
                drcModeEnterRequest.setOsdFrequency(1);
                drcModeEnterRequest.setHsiFrequency(2);
                flyApi.drcModeEnter(drcModeEnterRequest);

            }else{
                message = "参数错误";
                getFlyResultResponseDTO.setStatus(Boolean.FALSE);
            }
        } catch (Exception e){
            System.out.println(e.getMessage());
            reentrantLock.unlock();
        }finally {
            reentrantLock.unlock();
        }
        getFlyResultResponseDTO.setMessage(message);
        return getFlyResultResponseDTO;
    }

    @Override
    public GetFlyResultResponseDTO stickControl(FlyStickControlRequestDTO  flyStickControlRequestDTO) throws IOException {
        String message = "正常";
        GetFlyResultResponseDTO getFlyResultResponseDTO = new GetFlyResultResponseDTO();
        getFlyResultResponseDTO.setStatus(Boolean.TRUE);
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", flyStickControlRequestDTO.getId());
            if (ObjectUtil.isNotNull(flyStickControlRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", flyStickControlRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);
                StickControlRequest stickControlRequest = new StickControlRequest();
                stickControlRequest.setGateway(feisuanAirport.getGatewaySn());
                stickControlRequest.setYaw(flyStickControlRequestDTO.getYaw());
                stickControlRequest.setRoll(flyStickControlRequestDTO.getRoll());
                stickControlRequest.setPitch(flyStickControlRequestDTO.getPitch());
                stickControlRequest.setThrottle(flyStickControlRequestDTO.getThrottle());
                stickControlRequest.setGimbalPitch(flyStickControlRequestDTO.getGimbalPitch());
                flyApi.stickControl(stickControlRequest);
            }else{
                message = "参数错误";
                getFlyResultResponseDTO.setStatus(Boolean.FALSE);
            }
        } catch (Exception e){
            System.out.println(e.getMessage());
            reentrantLock.unlock();
        }finally {
            reentrantLock.unlock();
        }
        getFlyResultResponseDTO.setMessage(message);
        return getFlyResultResponseDTO;
    }

    @Override
    public Boolean flyToPoint(FlyRequestDTO editAirportRequestDTO) throws IOException {
        try {
            reentrantLock.lock();
            Long startTime = System.nanoTime();

            UpdateWrapper<FeisuanAirport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", editAirportRequestDTO.getId());
            if (ObjectUtil.isNotNull(editAirportRequestDTO)) {
                QueryWrapper<FeisuanAirport> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", editAirportRequestDTO.getId());
                FeisuanAirport feisuanAirport = airportMapper.selectOne(queryWrapper);
                updateWrapper.set("modify_time",LocalDateTime.now());

            }
            airportMapper.update(new FeisuanAirport(), updateWrapper);

            Long endTime = System.nanoTime();

            AddOperateLogRequest addOperateLogRequest = new AddOperateLogRequest();
            addOperateLogRequest.setOperateModule("飞控模块");
            addOperateLogRequest.setOperateName("编辑机场设备");
            addOperateLogRequest.setOperateResult(Boolean.TRUE);
            addOperateLogRequest.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
            addOperateLogRequest.setOperateType(1);
            addOperateLogRequest.setIpAddress(ActionUtils.getIpInfo());
            addOperateLogRequest.setExplorer(ActionUtils.getExplorerInfo());
            addOperateLogRequest.setTimes(endTime - startTime);
            operateLogApi.addOperateLogRequest(addOperateLogRequest);
        } finally {
            reentrantLock.unlock();
        }

        return Boolean.TRUE;
    }
}
